package docxlib

import (
	"encoding/xml"
	"io"
)

const (
	HYPERLINK_STYLE = "a1"
)

// A Run is part of a paragraph that has its own style. It could be
// a piece of text in bold, or a link
type Run struct {
	XMLName       xml.Name       `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main r,omitempty"`
	RunProperties *RunProperties `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main rPr,omitempty"`
	InstrText     string         `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main instrText,omitempty"`
	Text          *Text
}

// The Text object contains the actual text
type Text struct {
	XMLName  xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main t"`
	XMLSpace string   `xml:"xml:space,attr,omitempty"`
	Text     string   `xml:",chardata"`
}

// The hyperlink element contains links
type Hyperlink struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main hyperlink,omitempty"`
	ID      string   `xml:"http://schemas.openxmlformats.org/officeDocument/2006/relationships id,attr"`
	Run     Run
}

// RunProperties encapsulates visual properties of a run
type RunProperties struct {
	XMLName   xml.Name   `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main rPr,omitempty"`
	Color     *Color     `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main color,omitempty"`
	Size      *Size      `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main sz,omitempty"`
	RunStyle  *RunStyle  `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main rStyle,omitempty"`
	Style     *Style     `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main pStyle,omitempty"`
	Spacing   *Spacing   `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main spacing,omitempty"`
	Bold      *Bold      `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main b,omitempty"`
	SmallCaps *SmallCaps `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main smallCaps,omitempty"`
	Underline *Underline `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main u,omitempty"`
	Strike    *Strike    `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main strike,omitempty"`
	Highlight *Highlight `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main highlight,omitempty"`
	Positon   *Positon   `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main positon,omitempty"`
	VertAlign *VertAlign `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main vertAlign,omitempty"`
	Kern      *Kern      `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main kern,omitempty"`
}

// 行距
type Spacing struct {
	XMLName  xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main spacing,omitempty"`
	Before   int      `xml:"w:before,attr"`   //表示段前间距
	After    int      `xml:"w:after,attr"`    //表示段后间距
	Line     int      `xml:"w:line,attr"`     //表示行间距
	LineRule string   `xml:"w:lineRule,attr"` // 表示行距规则，可使用参数有‘auto,exact,atLeast’
	Val      int      `xml:"w:val,attr"`      //表示字符间距
}

type Bold struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main b,omitempty"`
}

// 将文本中小写字母转化为大写字母
type SmallCaps struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main smallCaps,omitempty"`
}

// 设置文本下划线样式 样式风格选择有：single,double,dots,dash,dotDash,dotDotDash,wave
type Underline struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main u,omitempty"`
	Val     string   `xml:"w:val,attr"`
}

// 设置文本删除线样式 样式风格选择有：single,double,none
type Strike struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main strike,omitempty"`
	Val     string   `xml:"w:val,attr"`
}

// 设置文本背景色，颜色的十六进制代码。
type Highlight struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main highlight,omitempty"`
	Val     string   `xml:"w:val,attr"`
}

// 设置文本的垂直位置,w:val 和 w:relativeFrom 属性一起使用，定义文本的垂直偏移。
type Positon struct {
	XMLName     xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main position,omitempty"`
	Val         int      `xml:"w:val,attr"`
	RelatieFrom string   `xml:"w:relatieFrom,attr"`
}

// 设置文本垂直对齐方式，选择方式是：superscript,subscript
type VertAlign struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main vertAlign,omitempty"`
	Val     string   `xml:"w:val,attr"`
}

// 设置文本垂直对齐方式，指定字符间距调整的绝对值（磅为单位）
type Kern struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main kern,omitempty"`
	Val     int      `xml:"w:val,attr"`
}

// RunStyle contains styling for a run
type RunStyle struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main rStyle,omitempty"`
	Val     string   `xml:"w:val,attr"`
}

// Style contains styling for a paragraph
type Style struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main pStyle,omitempty"`
	Val     string   `xml:"w:val,attr"`
}

// Color contains the sound of music. :D
// I'm kidding. It contains the color
type Color struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main color"`
	Val     string   `xml:"w:val,attr"`
}

// Size contains the font size
type Size struct {
	XMLName xml.Name `xml:"http://schemas.openxmlformats.org/wordprocessingml/2006/main sz"`
	Val     int      `xml:"w:val,attr"`
}

func (r *Run) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var elem Run
	for {
		t, err := d.Token()
		if err == io.EOF {
			break
		}

		switch tt := t.(type) {
		case xml.StartElement:
			if tt.Name.Local == "rPr" {
				var value RunProperties
				d.DecodeElement(&value, &start)
				elem.RunProperties = &value
			} else if tt.Name.Local == "instrText" {
				var value string
				d.DecodeElement(&value, &start)
				elem.InstrText = value
			} else if tt.Name.Local == "t" {
				var value Text
				d.DecodeElement(&value, &start)
				elem.Text = &value
			} else {
				continue
			}
		}

	}
	*r = elem

	return nil

}
func (r *Text) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var elem Text
	for {
		t, err := d.Token()
		if err == io.EOF {
			break
		}

		switch tt := t.(type) {
		case xml.CharData:
			cd := tt.Copy()
			elem.Text = string(cd)
		}

	}

	*r = elem
	return nil
}
func (r *Hyperlink) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var elem Hyperlink
	for {
		t, err := d.Token()
		if err == io.EOF {
			break
		}

		switch tt := t.(type) {
		case xml.StartElement:
			if tt.Name.Local == "r" {
				d.DecodeElement(&elem.Run, &start)
			} else {
				continue
			}
		}

	}
	*r = elem
	return nil

}
func (r *RunStyle) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
	var elem RunStyle
	for {
		t, err := d.Token()
		if err == io.EOF {
			break
		}

		switch tt := t.(type) {
		case xml.StartElement:
			elem.Val = getAtt(tt.Attr, "val")
		}

	}
	*r = elem
	return nil

}

func getAtt(atts []xml.Attr, name string) string {
	for _, at := range atts {
		if at.Name.Local == name {
			return at.Value
		}
	}
	return ""
}
